#include <sys/types.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "airkiss.h"


static uint8_t bcast_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

static uint16_t seqno = 0;

/* 
 *  8  7  6  5  4  3  2  1  0
 *  1: data
 *  0  1: sequence header
 *  0  0: 0~3: magic code, 
 *        4~7: prefix code 
 */

struct sta_info {
	uint8_t mac[ETH_ALEN];
	uint8_t buf[MAX_BUF_SIZE];
	int     cnt;
	int		pos;
	int		base_len;
};

#define MAX_STA_NUM		64
static struct sta_info info[MAX_STA_NUM] = {{{0}, {0}, 0, 0, 0},};
#define MIN_PREAMBLE_CNT	3
#define MIN_MAGIC_CNT		2

static int sta_index = 0;

int find_sta_index(uint8_t *addr)
{
	int i;
	for (i = 0; i < MAX_STA_NUM; i++)
		if (!memcmp(info[i].mac, addr, ETH_ALEN))
			return i;

	// append to info
	if (sta_index >= MAX_STA_NUM)
		return -1;

	memcpy(info[sta_index].mac, addr, ETH_ALEN);

	sta_index++;

	return sta_index - 1;
}

void append_sniffer_data(uint8_t *addr, int len)
{
	int index;

	index = find_sta_index(addr);
	if (index >= 0) {
		// append data
		info[index].buf[info[index].pos] = len;
		info[index].pos++;
		info[index].pos = (info[index].pos) % MAX_BUF_SIZE;
		info[index].cnt++;
	} else {
		printf("cannot find proper slot fot addr\n");
	}
}

int find_preamble(void)
{
	int i, j;
	int len;
	int pream_cnt = 0;
	uint8_t *b;

	for (i = 0; i < sta_index; i++) {
		if (info[i].cnt > 32) {
			// check wether have received preamble
			len = info[i].cnt < MAX_BUF_SIZE ? info[i].cnt : MAX_BUF_SIZE;
			b = info[i].buf;

			for (j = 0; j < len; ) {
				if (b[j+3] - b[j+2] == 1 &&
					b[j+2] - b[j+1] == 1 &&
					b[j+1] - b[j] == 1) {

					j += 4;
					pream_cnt++;
					info[i].base_len = b[j];

					if (pream_cnt > MIN_PREAMBLE_CNT)
						return i;	// return sta info
				} else {
					j++;
				}
			}
		}
	}

	return -1;
}


/* ALL information are all in len */
int airkiss_recv(struct airkiss_context *ac, uint8_t *packet, int len)
{
	uint8_t *p;
	uint8_t *sa;
	uint16_t fc;	// frame control 
	uint16_t seq;
	int i;
	uint8_t cod;
	int dat;

	// sanity check, discard non-insteresting packets.
	if (!packet || len < 24)
		return 1;

	fc = packet[0] << 8 | packet[1];

	if (!(fc & 0x0800))
		return 1;	// Data

	if ((fc & 0x3) != 0x2)
		return 1;	// FromDS: 1, ToDS: 0

	p = packet + 4;	// DA
	if (memcmp(p, bcast_mac, ETH_ALEN))
		return 1;	// DA should be FF:FF:FF:FF:FF:FF

	// addr 3
	sa = packet + 16;

	// stage1:
	// try to receive PREAMBLE
	// PREABLE is a sequence with ...., for example, 41, 42, 43, 44, 41, 42, 43, 44, ....
	
	if (ac->status == 0) {
		int pos;
		append_sniffer_data(sa, len);

		printf("preamble len %d\n", len);
		pos = find_preamble();
		if (pos >= 0) {
			// preamble has received
			ac->status |= PREAMBLE_RXD;

			memcpy(ac->addr, info[pos].mac, ETH_ALEN);
			ac->base_len = info[pos].base_len;
			printf("rxed preamble for %02X:%02X:%02X:%02X:%02X:%02X\n", 
				ac->addr[0], ac->addr[1], ac->addr[2],
				ac->addr[3], ac->addr[4], ac->addr[5]);
		}
		return 0;
	}

	// skip packets that mac addr not match
	if (memcmp(sa, ac->addr, ETH_ALEN))
		return 1;

	printf("len %d\n", len);

	// stage2: 
	if ((len & (BIT(7) | BIT(8))) == 0) {
		// magic code or prefix code

		cod = (len & 0x70) >> 4;
		dat = len & 0xF;

		if (cod <= 3) {
			// MAGIC CODE
			if (ac->status & MAGIC_RXD)
				return 0;

			ac->flag |= BIT(cod);
			switch (cod) {
				case 0:	// length high
					ac->total_len |= dat << 4;
					break;
				case 1:
					ac->total_len |= dat;
					break;
				case 2:
					ac->ssid_crc |= dat << 4;
					break;
				case 3:
					ac->ssid_crc |= dat;
					break;
			}

			if ((ac->flag & 0xF) == 0xF) {
				// fully received magic code (4 packets)
				// check whether it is valid
				if (ac->total_len == ac->total_len_saved &&
					ac->ssid_crc == ac->ssid_crc_saved) {
					ac->magic_cnt++;
					if (ac->magic_cnt > MIN_MAGIC_CNT) {
						printf("RXD preamble magic code, length %d, ssid crc 0x%x\n", 
							ac->total_len, ac->ssid_crc);
						ac->status |= MAGIC_RXD;
					}
				} else {
					ac->total_len_saved = ac->total_len;
					ac->ssid_crc_saved = ac->ssid_crc;
					ac->magic_cnt = 0;
				}

				// next time
				ac->flag &= ~0x0F;
			}

		} else {
			// PREFIX CODE
			if (ac->status & PREFIX_RXD)
				return 0;
			ac->flag |= BIT(cod);
			switch (cod) {
				case 4:
					ac->pass_len |= dat << 4;
					break;
				case 5:
					ac->pass_len |= dat;
					break;
				case 6:
					ac->pass_crc |= dat << 4;
					break;
				case 7:
					ac->pass_crc |= dat;
					break;
				default:
					// error packet
					break;
			}
			if ((ac->flag & 0xF0) == 0xF0) {
				// check prefix code valid
				ac->status |= PREFIX_RXD;
			}
		}

	}

	// stage2: 
	// receive prefix code
	if ((len & BIT(7)) == BIT(7)) {
		// seq data
		if (ac->seq_step == 0) {
			// seq crc8 (lower 7bits)
			ac->seq_no_crc = len & 0x7F;
			ac->seq_step = 1;

			printf("seq no crc %d\n", ac->seq_no_crc);

		} else if (ac->seq_step == 1) {
			// seq index
			ac->seq_no = len & (~(BIT(8) | BIT(7)));
			ac->index[ac->seq_no] = 1;
			ac->pos = ac->seq_no << 2; // *4
			printf("seq no %d\n", ac->seq_no);

			ac->seq_step = 0;
		}
	}

	// stage 3:
	// receive sequence header + data field
	if (len & BIT(8)) {
		//ac->buf[ac->seq_no]  = len & ~(BIT(8));
		ac->buf[ac->pos++] = len & ~(BIT(8));
		printf("data %d\n", len & ~(BIT(8)));
		//ac->pos++;
	}

	if (ac->pos >= ac->total_len) {
		// check whether all packets are received
		for (i = 0; i < ac->total_len; i++)
			if (!ac->index[i])
				return 0;
	}

#if 0
	// ok, all packets are received
{
	char passwd[32];
	char ssid[32];
	int ssid_len = ac->total_len - ac->pass_len - 1;
	uint8_t random;

	strncpy(passwd, ac->buf, ac->pass_len);
	passwd[ac->pass_len] = '\0';

	strncpy(ssid, &ac->buf[ac->pass_len + 1], ssid_len);
	ssid[ssid_len] = '\0';

	random = ac->buf[ac->pass_len];

	printf("ssid: %s, passwd: %s, random: %d\n", ssid, passwd, random);
}
#endif
	
	return 0;
}


